﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FifaChamps.API.Data;

namespace FifaChamps.API.Logic
{
    public abstract class Fixture
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public FixtureResult HomePlayer { get; set; }
        public FixtureResult AwayPlayer { get; set; }

        #region Instance Methods

        public virtual void Save()
        {
            this.HomePlayer.Save();
            this.AwayPlayer.Save();
        }

        public virtual bool Set_HomeResult(EndResult result, int goalsFor, int goalsAgainst)
        {
            return Set_PlayerResult(this.HomePlayer, result, goalsFor, goalsAgainst);
        }

        public virtual bool Set_AwayResult(EndResult result, int goalsFor, int goalsAgainst)
        {
            return Set_PlayerResult(this.AwayPlayer, result, goalsFor, goalsAgainst);
        }

        private bool Set_PlayerResult(FixtureResult playerResult, EndResult result, int goalsFor, int goalsAgainst)
        {
            playerResult.ResultType = result;
            playerResult.GoalsFor = goalsFor;
            playerResult.GoalsAgainst = goalsAgainst;

            return true; 
        }

        #endregion

        #region Static Methods

        public static Fixture Get_One(int fixtureID, StageType type)
        {
            Fixture fixture = null;
            switch (type)
            {
                case StageType.Knockout:
                    fixture = KnockoutFixture.Get_One(fixtureID);
                    break;
            }

            return fixture;
        }
        public static Fixture Add_Fixture(StageType type, int phaseID, string name, int homePlayer, int awayPlayer)
        {
            switch (type)
            {
                case StageType.Knockout:
                    return KnockoutFixture.Add_Fixture(phaseID, name, homePlayer, awayPlayer);
                    break;
                case StageType.Group:
                    return GroupFixture.Add_Fixture(phaseID, name, homePlayer, awayPlayer);
                    break;
            }

            return null;
        }

        #endregion

    }

    public class KnockoutFixture : Fixture
    {
        internal KnockoutFixture(int id, string name)
        {
            this.ID = id;
            this.Name = name;
        }

        internal static KnockoutFixture Get_One(int fixtureID)
        {
            var ko_fixture_data = DataManager.Get_KnockoutFixture(fixtureID);
            KnockoutFixture ko = new KnockoutFixture(ko_fixture_data.FixtureID, ko_fixture_data.FixtureName);
            var away_result = ko_fixture_data.Results.Where(x => !x.Home.Value).First();
            var home_result = ko_fixture_data.Results.Where(x => x != away_result).First();

            if (home_result != null) ko.HomePlayer = FixtureResult.Factory(home_result.ResultID, home_result.FixtureID, home_result.GoalsFor, home_result.GoalsAgainst, home_result.Home, home_result.PlayerKnockoutResultID, home_result.ResultTypeID.HasValue ? (int) home_result.ResultTypeID.Value : (int) EndResult.Unknown);
            if (away_result != null) ko.AwayPlayer = FixtureResult.Factory(away_result.ResultID, away_result.FixtureID, away_result.GoalsFor, away_result.GoalsAgainst, away_result.Home, away_result.PlayerKnockoutResultID, away_result.ResultTypeID.HasValue ? (int) away_result.ResultTypeID.Value : (int)EndResult.Unknown);

            return ko;
        }

        internal static KnockoutFixture Add_Fixture(int phaseID, string name, int phasehomePlayer, int phaseawayPlayer)
        {
            int fixtureID = DataManager.Add_Fixture(name); //add fixture
            int homeID = DataManager.Add_FixtureResult(fixtureID, default(int?), default(int?), default(int?), true); //add home fixture
            int awayID = DataManager.Add_FixtureResult(fixtureID, default(int?), default(int?), default(int?), false); //add away fixture

            int playerkohomeplayerID = DataManager.Add_FixtureResult_KOPlayer(homeID, phasehomePlayer);
            int playerkoawayplayerID = DataManager.Add_FixtureResult_KOPlayer(awayID, phaseawayPlayer);

            return Get_One(fixtureID);
        }        
    }

    public class GroupFixture : Fixture
    {
        internal GroupFixture(int id, string name)
        {
            this.ID = id;
            this.Name = name;
        }

        internal static GroupFixture Get_One(int fixtureID)
        {
            var gr_fixture_data = DataManager.Get_GroupFixture(fixtureID);
            GroupFixture ko = new GroupFixture(gr_fixture_data.FixtureID, gr_fixture_data.FixtureName);
            var away_result = gr_fixture_data.Results.Where(x => !x.Home.Value).First();
            var home_result = gr_fixture_data.Results.Where(x => x != away_result).First();

            if (home_result != null) ko.HomePlayer = FixtureResult.Factory(home_result.ResultID, home_result.FixtureID, home_result.GoalsFor, home_result.GoalsAgainst, home_result.Home, home_result.PlayerGroupResultID, home_result.ResultTypeID.HasValue ? (int)home_result.ResultTypeID.Value : (int)EndResult.Unknown);
            if (away_result != null) ko.AwayPlayer = FixtureResult.Factory(away_result.ResultID, away_result.FixtureID, away_result.GoalsFor, away_result.GoalsAgainst, away_result.Home, away_result.PlayerGroupResultID, away_result.ResultTypeID.HasValue ? (int)away_result.ResultTypeID.Value : (int)EndResult.Unknown);

            return ko;
        }

        internal static GroupFixture Add_Fixture(int phaseID, string name, int phasehomePlayer, int phaseawayPlayer)
        {
            int fixtureID = DataManager.Add_Fixture(name); //add fixture
            int homeID = DataManager.Add_FixtureResult(fixtureID, default(int?), default(int?), default(int?), true); //add home fixture
            int awayID = DataManager.Add_FixtureResult(fixtureID, default(int?), default(int?), default(int?), false); //add away fixture

            DataManager.Add_FixtureResult_GroupPlayer(homeID, phasehomePlayer);
            DataManager.Add_FixtureResult_GroupPlayer(awayID, phaseawayPlayer);

            return Get_One(fixtureID);
        }  
    }

    public class SeasonFixture : Fixture
    { 
    }

    public class FixtureResult
    {
        public int ID { get; set; }
        public int FixtureID { get; set; }
        public EndResult ResultType { get; set; }
        public int? GoalsFor { get; set; }
        public int? GoalsAgainst { get; set; }
        public bool? Home { get; set; }
        public int PhasePlayerID { get; set; }

        #region Constructors        

        private FixtureResult()
        {
            this.ID = default(int);
            this.FixtureID = default(int);
            this.GoalsFor = default(int?);
            this.GoalsAgainst = default(int?);
            this.Home = default(bool?);
            this.PhasePlayerID = default(int);
        }

        private FixtureResult(int fixtureID, int? goalsFor, int? goalsAgainst,
            bool? home, int phasePlayerID) : this(default(int), fixtureID, goalsFor, goalsAgainst, home, phasePlayerID, default(int))
        {
        }

        private FixtureResult(int id, int fixtureID, int? goalsFor, int? goalsAgainst,
            bool? home, int phasePlayerID, int? resultID) : this()
        {
            this.ID = id;
            this.FixtureID = fixtureID;
            this.GoalsFor = goalsFor;
            this.GoalsAgainst = goalsAgainst;
            this.Home =  home;
            this.PhasePlayerID = phasePlayerID;
            this.ResultType = (EndResult)resultID;
        }

        #endregion

        #region Factory        

        public static FixtureResult Factory(int fixtureID, int phasePlayerID)
        {
            return Factory(fixtureID, default(int?), default(int?), default(bool?), phasePlayerID);
        }

        public static FixtureResult Factory(int fixtureID, int? goalsFor, int? goalsAgainst, bool? home, int phasePlayerID)
        {
            return new FixtureResult(fixtureID, goalsFor, goalsAgainst, home, phasePlayerID);
        }

        public static FixtureResult Factory(int fixtureResultID, int fixtureID, int? goalsFor, int? goalsAgainst, bool? home, int phasePlayerID, int? resultTypeID)
        {
            return new FixtureResult(fixtureResultID,fixtureID, goalsFor, goalsAgainst, home, phasePlayerID, resultTypeID);
        }

        #endregion

        internal void Save()
        {
            DataManager.Update_FixtureResult(this.ID, this.FixtureID, (int)this.ResultType, this.GoalsFor, this.GoalsAgainst, this.Home);
        }
    }
}
